-module(test_graph).
-include_lib("eunit/include/eunit.hrl").
-include_lib("../../adt/graph.hrl").

adt_test() ->
    g_new_test(),
    g_addVertex_test(),
    g_deleteVertex_test(),
    g_getVertexes_test(),
    g_addEdgeU_test(),
    g_addEdgeD_test(),
    g_deleteEdgeD_test(),
    g_setValE_test(),
    g_setStrE_test(),
    g_setValV_test(),
    g_getValE_test(),
    g_getStrE_test(),
    g_getValV_test(),
    g_getStrV_test(),
    g_getAttrV_test(),
    g_getAttrE_test(),
    g_getSource_test(),
    g_getTarget_test(),
    g_getAdjacent_test(),
    g_getIncident_test(),
    g_schlaufen_test(),
    g_isEmpty_test().

g_new_test() ->
    G = graph:new(),
    ?assert(graph:getVertexes(G) =:= []),
    ?assert(graph:getEdges(G) =:= []).


g_isEmpty_test() ->
    G = graph:new(),
    ?assert(graph:isEmpty(G) =:= true),
    {G1, _} = graph:addVertex(G, v),
    ?assert(graph:isEmpty(G1) =:= false).


g_addVertex_test() ->
    G = graph:new(),
    ?assert(graph:getVertexes(G) =:= []),
    {G1, ID_v} = graph:addVertex(G, v),
    [Vertex] = G1#graph.vertexes,
    ?assert(Vertex =:= {ID_v, [{vertex, ID_v, v, []}]}),
    ?assert(Vertex /= {vertex, ID_v, c, []}),
    {G2, ID_v_2} = graph:addVertex(G1, v),
    ?assert(ID_v_2 =:= ID_v),
    [Vertex2] = G2#graph.vertexes,
    ?assert(Vertex2 =:= {ID_v, [{vertex, ID_v, v, []}]}).
    
g_deleteVertex_test() ->
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_c} = graph:addVertex(G1, c),
    {G3, ID_b} = graph:addVertex(G2, b),
    {G4, ID_edge_v_c} = graph:addEdgeU(G3, ID_v, ID_c),
    G5 = graph:deleteVertex(G4, ID_v),
    V = graph:getVertexes(G5),
    ?assert(lists:flatlength(V) =:= 2),
    ?assert(lists:member(ID_c, V)),
    ?assert(lists:member(ID_b, V)),
    ?assert(graph:getEdges(G5) =:= []).

g_getVertexes_test() ->
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    ?assert(graph:getVertexes(G1) =:= [ID_v]),
    {G2, ID_c} = graph:addVertex(G1, c),
    if
        ID_v < ID_c -> L = [ID_v, ID_c];
        true -> L = [ID_c, ID_v]
    end,
    ?assert(graph:getVertexes(G2) =:= L).

%% TODO Test des Kantentypes
g_addEdgeU_test() ->
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_c} = graph:addVertex(G1, c),
    {G3, ID_edge_v_c} = graph:addEdgeU(G2, ID_v, ID_c),
    [Edge_v_c] = graph:getEdges(G3),
    ?assert(ID_edge_v_c =:= Edge_v_c),
    {G4, _ID_edge_c_v} = graph:addEdgeU(G3, ID_c, ID_v),
    L = graph:getEdges(G4),
    ?assert(lists:flatlength(L) =:= 2).

%% TODO Test des Kantentypes
g_addEdgeD_test() ->
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_c} = graph:addVertex(G1, c),
    {G3, ID_edge_v_c} = graph:addEdgeD(G2, ID_v, ID_c),
    [Edge_v_c] = graph:getEdges(G3),
    ?assert(ID_edge_v_c =:= Edge_v_c),
    {G4, _ID_edge_c_v} = graph:addEdgeD(G3, ID_c, ID_v),
    L = graph:getEdges(G4),
    ?assert(lists:flatlength(L) =:= 2).

g_deleteEdgeD_test() ->
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_c} = graph:addVertex(G1, c),
    {G3, ID_b} = graph:addVertex(G2, b),
    {G4, _} = graph:addEdgeD(G3, ID_v, ID_c),
    {G5, ID_edge_v_b} = graph:addEdgeD(G4, ID_v, ID_b),
    G6 = graph:deleteEdge(G5, ID_v, ID_c),
    [Edge_v_b] = graph:getEdges(G6),
    ?assert(ID_edge_v_b =:= Edge_v_b).

g_setValE_test() ->
    C1 = 5,
    C2 = 0,
    H1 = 6,
    H2 = 0,
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_c} = graph:addVertex(G1, c),
    {G3, ID_edge_v_c} = graph:addEdgeD(G2, ID_v, ID_c),
    G4 = graph:setValE(G3, ID_edge_v_c, c, C1),
    G5 = graph:setValE(G4, ID_edge_v_c, h, H1),
    [Edge_v_c] = graph:getEdges(G5),
    Value = case orddict:find(Edge_v_c, G5#graph.edges) of
        {ok, V} -> [R] = V, R;
        error       -> false
    end,
    Attribs = Value#edge.attr,
    ?assert(proplists:get_value(c, Attribs) =:= [C1]),
    ?assert(proplists:get_value(h, Attribs) =:= [H1]),
    G6 = graph:setValE(G5, ID_edge_v_c, c, C2),
    G7 = graph:setValE(G6, ID_edge_v_c, h, H2),
    [Edge_v_c_2] = graph:getEdges(G7),

    Value_2 = case orddict:find(Edge_v_c_2, G7#graph.edges) of
        {ok, V_2} -> [R_2] = V_2, R_2;
        error       -> false
    end,
    Attribs_1 = Value_2#edge.attr,
    ?assert(proplists:get_value(c, Attribs_1) =:= [C2]),
    ?assert(proplists:get_value(h, Attribs_1) =:= [H2]).

g_setStrE_test() ->
    C1 = "TEST",
    C2 = "TEST1",
    H1 = "C",
    H2 = "G",
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_c} = graph:addVertex(G1, c),
    {G3, ID_edge_v_c} = graph:addEdgeD(G2, ID_v, ID_c),
    G4 = graph:setStrE(G3, ID_edge_v_c, c, C1),
    G5 = graph:setStrE(G4, ID_edge_v_c, h, H1),
    [Edge_v_c] = graph:getEdges(G5),
    Value = case orddict:find(Edge_v_c, G5#graph.edges) of
        {ok, V} -> [R] = V, R;
        error       -> false
    end,
    Attribs = Value#edge.attr,
    ?assert(proplists:get_value(c, Attribs) =:= [C1]),
    ?assert(proplists:get_value(h, Attribs) =:= [H1]),
    G6 = graph:setStrE(G5, ID_edge_v_c, c, C2),
    G7 = graph:setStrE(G6, ID_edge_v_c, h, H2),
    [Edge_v_c_2] = graph:getEdges(G7),
    Value_2 = case orddict:find(Edge_v_c_2, G7#graph.edges) of
        {ok, V_2} -> [R_2] = V_2, R_2;
        error       -> false
    end,
    Attribs_1 = Value_2#edge.attr,
    ?assert(proplists:get_value(c, Attribs_1) =:= [C2]),
    ?assert(proplists:get_value(h, Attribs_1) =:= [H2]).

g_setValV_test() ->
    C1 = 5,
    C2 = 0,
    H1 = 6,
    H2 = 0,
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    G2 = graph:setValV(G1, ID_v, c, C1),
    G3 = graph:setValV(G2, ID_v, h, H1),
    [Vertex_v] = graph:getVertexes(G3),
        
    Value = case orddict:find(Vertex_v, G3#graph.vertexes) of
        {ok, V} -> [R] = V, R;
        error       -> false
    end,
    Attribs = Value#vertex.attr,
    ?assert(proplists:get_value(c, Attribs) =:= [C1]),
    ?assert(proplists:get_value(h, Attribs) =:= [H1]),
    G4 = graph:setValV(G3, ID_v, c, C2),
    G5 = graph:setValV(G4, ID_v, h, H2),
    [Vertex_v_2] = graph:getVertexes(G5),
    
    Value_2 = case orddict:find(Vertex_v_2, G5#graph.vertexes) of
        {ok, V_2} -> [R_2] = V_2, R_2;
        error       -> false
    end,
    Attribs_2 = Value_2#vertex.attr,
    ?assert(proplists:get_value(c, Attribs_2) =:= [C2]),
    ?assert(proplists:get_value(h, Attribs_2) =:= [H2]).
    
g_getValE_test() ->
    C1 = 5,
    C2 = 0,
    H1 = 6,
    H2 = 0,
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_b} = graph:addVertex(G1, b),
    {G3, ID_edge_v_b} = graph:addEdgeD(G2, ID_v, ID_b),
    G4 = graph:setValE(G3, ID_edge_v_b, c, C1),
    G5 = graph:setValE(G4, ID_edge_v_b, h, H1),
    ?assert(graph:getValE(G5, ID_edge_v_b, c) =:= C1),
    ?assert(graph:getValE(G5, ID_edge_v_b, h) =:= H1),
    G6 = graph:setValE(G5, ID_edge_v_b, c, C2),
    G7 = graph:setValE(G6, ID_edge_v_b, h, H2),
    ?assert(graph:getValE(G7, ID_edge_v_b, c) =:= C2),
    ?assert(graph:getValE(G7, ID_edge_v_b, h) =:= H2).

g_getStrE_test() ->
    C1 = "TEST",
    C2 = "TEST1",
    H1 = "T",
    H2 = "G",
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_b} = graph:addVertex(G1, b),
    {G3, ID_edge_v_b} = graph:addEdgeD(G2, ID_v, ID_b),
    G4 = graph:setStrE(G3, ID_edge_v_b, c, C1),
    G5 = graph:setStrE(G4, ID_edge_v_b, h, H1),
    ?assert(graph:getStrE(G5, ID_edge_v_b, c) =:= C1),
    ?assert(graph:getStrE(G5, ID_edge_v_b, h) =:= H1),
    G6 = graph:setStrE(G5, ID_edge_v_b, c, C2),
    G7 = graph:setStrE(G6, ID_edge_v_b, h, H2),
    ?assert(graph:getStrE(G7, ID_edge_v_b, c) =:= C2),
    ?assert(graph:getStrE(G7, ID_edge_v_b, h) =:= H2).

g_getValV_test() ->
    C1 = 5,
    C2 = 0,
    H1 = 6,
    H2 = 0,
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    G2 = graph:setValV(G1, ID_v, c, C1),
    G3 = graph:setValV(G2, ID_v, h, H1),
    ?assert(graph:getValV(G3, ID_v, c) =:= C1),
    ?assert(graph:getValV(G3, ID_v, h) =:= H1),
    G4 = graph:setValV(G3, ID_v, c, C2),
    G5 = graph:setValV(G4, ID_v, h, H2),
    ?assert(graph:getValV(G5, ID_v, c) =:= C2),
    ?assert(graph:getValV(G5, ID_v, h) =:= H2).

g_getStrV_test() ->
    C1 = "TEST",
    C2 = "TEST5",
    H1 = "B",
    H2 = "A",
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    G2 = graph:setStrV(G1, ID_v, c, C1),
    G3 = graph:setStrV(G2, ID_v, h, H1),
    ?assert(graph:getStrV(G3, ID_v, c) =:= C1),
    ?assert(graph:getStrV(G3, ID_v, h) =:= H1),
    G4 = graph:setStrV(G3, ID_v, c, C2),
    G5 = graph:setStrV(G4, ID_v, h, H2),
    ?assert(graph:getStrV(G5, ID_v, c) =:= C2),
    ?assert(graph:getStrV(G5, ID_v, h) =:= H2).

g_getAttrV_test() ->
    C1 = 5,
    C2 = 0,
    H1 = 6,
    H2 = 0,
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    G2 = graph:setValV(G1, ID_v, c, C1),
    G3 = graph:setValV(G2, ID_v, h, H1),
    ?assert(graph:getAttrV(G3, ID_v) =:= [{c,[C1]},{h,[H1]}]),
    G4 = graph:setValV(G3, ID_v, c, C2),
    G5 = graph:setValV(G4, ID_v, h, H2),
    ?assert(graph:getAttrV(G5, ID_v) =:= [{c,[C2]},{h,[H2]}]).

g_getAttrE_test() ->
    C1 = 5,
    C2 = 0,
    H1 = 6,
    H2 = 0,
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_b} = graph:addVertex(G1, b),
    {G3, ID_edge_v_b} = graph:addEdgeD(G2, ID_v, ID_b),
    G4 = graph:setValE(G3, ID_edge_v_b, c, C1),
    G5 = graph:setValE(G4, ID_edge_v_b, h, H1),
    ?assert(graph:getAttrE(G5, ID_edge_v_b) =:= [{c,[C1]},{h,[H1]}]),
    G6 = graph:setValE(G5, ID_edge_v_b, c, C2),
    G7 = graph:setValE(G6, ID_edge_v_b, h, H2),
    ?assert(graph:getAttrE(G7, ID_edge_v_b) =:= [{c,[C2]},{h,[H2]}]).
    
g_getSource_test() ->
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_b} = graph:addVertex(G1, b),
    {G3, ID_c} = graph:addVertex(G2, c),
    {G4, ID_edge_v_b} = graph:addEdgeD(G3, ID_v, ID_b),    
    {G5, ID_edge_v_c} = graph:addEdgeU(G4, ID_v, ID_c),
    ?assert(graph:getSource(G5, ID_edge_v_b) =:= ID_v),
    ?assert(graph:getSource(G5, ID_edge_v_c) =:= ID_v).

g_getTarget_test() ->
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_b} = graph:addVertex(G1, b),
    {G3, ID_c} = graph:addVertex(G2, c),
    {G4, ID_edge_v_b} = graph:addEdgeD(G3, ID_v, ID_b),
    {G5, ID_edge_v_c} = graph:addEdgeU(G4, ID_v, ID_c),
    ?assert(graph:getTarget(G5, ID_edge_v_b) =:= ID_b),
    ?assert(graph:getTarget(G5, ID_edge_v_c) =:= ID_c).

g_getAdjacent_test() ->
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_b} = graph:addVertex(G1, b),
    {G3, ID_c} = graph:addVertex(G2, c),
    {G4, ID_d} = graph:addVertex(G3, d),
    {G5, _} = graph:addEdgeD(G4, ID_v, ID_b),    
    {G6, _} = graph:addEdgeU(G5, ID_c, ID_v),
    {G7, _} = graph:addEdgeD(G6, ID_c, ID_d),
    L = graph:getAdjacent(G7, ID_v),
    ?assert(lists:flatlength(L) =:= 2),
    ?assert(lists:member(ID_b, L)),
    ?assert(lists:member(ID_c, L)).

g_getIncident_test() ->
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_b} = graph:addVertex(G1, b),
    {G3, ID_c} = graph:addVertex(G2, c),
    {G4, ID_d} = graph:addVertex(G3, d),
    {G5, ID_Edge_v_b} = graph:addEdgeD(G4, ID_v, ID_b),    
    {G6, ID_Edge_c_v} = graph:addEdgeU(G5, ID_c, ID_v),
    {G7, _} = graph:addEdgeD(G6, ID_c, ID_d),
    L = graph:getIncident(G7, ID_v),
    ?assert(lists:flatlength(L) =:= 2),
    ?assert(lists:member(ID_Edge_v_b, L)),
    ?assert(lists:member(ID_Edge_c_v, L)).

g_schlaufen_test() ->
    G = graph:new(),
    {G1, ID_v} = graph:addVertex(G, v),
    {G2, ID_Edge_v_v} = graph:addEdgeD(G1, ID_v, ID_v),
    A = graph:getAdjacent(G2, ID_v),
    I = graph:getIncident(G2, ID_v),
    [AV] = A,
    [IV] = I,
    ?assert(AV =:= ID_v),
    ?assert(IV =:= ID_Edge_v_v).
